from asyncio import CancelledError
import cv2
from cv2 import erode
from cv2 import dilate
import numpy as np

# 滤除的最小矩形的范围
min_w = 90
min_h = 90

# 定义检测线的高度，与视频大小有关，视频左上角为（0，0）
line_high = 550
# 线的偏移量
offset = 7

# 统计车的数量
carno = 0

# 存放有效车辆的数组
cars = []

# 求车的中心点
def center(x,y,w,h):
    x1 = int(w/2)
    y1 = int(h/2)
    cx = x + x1
    cy = y + y1
    return cx,cy

cap = cv2.VideoCapture('E:\\video.mp4') #加载视频

bgsubmog = cv2.createBackgroundSubtractorMOG2()

# 形态学kernel
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))

while True:
    ret, frame = cap.read()

    if (ret == True) :
        
        # 灰度化处理
        cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        # print(frame.shape)   # 获取视频大小的信息
        # exit()   # 该命令之后的所有程序都不执行
        # 去噪（高斯）
        blur = cv2.GaussianBlur(frame, (7,7),5)
        # 去背景
        mask = bgsubmog.apply(blur)
        # 腐蚀
        erode = cv2.erode(mask, kernel)
        # 膨胀
        dilate = cv2.dilate(erode, kernel, iterations= 2)

        # 形态学闭运算，去除图像里面的噪点
        close = cv2.morphologyEx(dilate, cv2.MORPH_CLOSE, kernel)

        # 查找轮廓
        cnts, h = cv2.findContours(close, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
        
        # 绘制一条检测线
        cv2.line(frame, (10,line_high),(1200, line_high),(255,255,0),3)

        # 对所有轮廓进行遍历
        for (i, c) in enumerate(cnts):
            (x,y,w,h) = cv2.boundingRect(c)
           
            # 对车辆的宽高进行判断，以验证是否为有效的车辆
            isValid = (w >= min_w) and ( h >= min_h)
            if( not isValid):
                continue
            # 到这里都是有效的车，绘制车的矩形
            cv2.rectangle(frame, (x,y),(x+w,y+h),(0,0,255),2)
            # 存储车的中心点
            cpoint = center(x,y,w,h)    # 计算车的中心点
            cars.append(cpoint)    # 将中心点数据存储到cars这个数组中

            for (x,y) in cars :   # 遍历数组，如果车的中心点落在检测线的有效区域内，则计数+1，然后去除该数组
                if ((y > line_high - offset) and (y < line_high + offset)):
                    carno += 1
                    cars.remove((x,y))  
                    print(carno)
        # 显示统计信息
        cv2.putText(frame, "Cars Count:" + str(carno),(500,60), cv2.FONT_HERSHEY_SIMPLEX, 2, (255, 0, 0), 5)   
        cv2.imshow('video', frame)
        # cv2.imshow('close', close)   
    key = cv2.waitKey(1)
    if(key == 27) : # esc键
        break

cap.release()
cv2.destroyAllWindows()